<template>
    <div :class="['v-field', type, { plain: plain }]">
        <div v-if="label" class="lab">{{ label }}</div>

        <template v-if="type == 'select'">
            <div class="con">
                <select
                    v-model="currentValue"
                    :placeholder="placeholder"
                    @focus="handleFocus"
                    @change="handleChange"
                    v-validator="validator"
                >
                    <!-- <option value="" disabled selected style="display:none;">Please Choose</option> -->
                    <template v-for="(obj, idx) in options">
                        <template v-if="obj.hidden">
                            <option value="" :key="idx" selected disabled class="placeholder">
                                {{ obj.label || obj }}
                            </option>
                        </template>
                        <template v-else>
                            <option :value="obj.value !== undefined ? obj.value : obj" :key="idx">
                                {{ obj.label || obj }}
                            </option>
                        </template>
                    </template>
                </select>
            </div>
        </template>

        <template v-else-if="type == 'switch'">
            <div class="con switch" @click="hanldeSwitch">
                <i class="icon" :class="[this.currentValue ? 'icon-selected' : 'icon-select']" />
            </div>
        </template>

        <template v-else-if="type == 'point'">
            <div class="con">
                <input
                    type="text"
                    v-model="currentValue['x']"
                    :placeholder="'X'"
                    @focus="handleFocus"
                    v-validator="validator"
                />
                <input
                    type="text"
                    v-model="currentValue['y']"
                    :placeholder="'Y'"
                    @focus="handleFocus"
                    v-validator="validator"
                />
            </div>
        </template>

        <template v-else-if="type == 'rgba'">
            <div class="rgbaInputFrame" @click="openDropdownBoxListener">
                <div ref="colorBox" class="rgbaInputColorBox" :style="boxStyle"></div>
                <input
                    type="text"
                    class="rgbaInputHexBox"
                    v-model="currentValueHex"
                    :placeholder="placeholder"
                    readonly="readonly"
                    v-validator="validator"
                />
                <div ref="dropdownBox" class="rgbaDropdownBox" v-if="dropdownBoxVisible">
                    <template v-for="(c, i) in hexBoxCols" :key="'c' + i">
                        <div
                            class="rgbaDropdownBoxColumn"
                            :style="c.style"
                            @mousedown="e => colPointerDownListener(e, i)"
                            @touchstart="e => colPointerDownListener(e, i)"
                        >
                            <div class="rgbaDropdownBoxMarker" :style="c.childStyle"></div>
                        </div>
                    </template>

                    <template v-for="(c, i) in usedColors" :key="'u' + i">
                        <div
                            :class="c.class"
                            :style="c.style"
                            @click="setColor(c.style.background)"
                        ></div>
                    </template>
                </div>
            </div>
        </template>

        <template v-else>
            <div class="con">
                <input
                    :type="type"
                    v-model="currentValue"
                    :placeholder="placeholder"
                    @focus="handleFocus"
                    v-validator="validator"
                />
            </div>
        </template>
    </div>
</template>

<script>
import * as Utils from '../core/utils.js';
import * as DOM from '../core/DOM.js';
import * as Expert from './Expert.js';
import _ from 'lodash';
import bus from '../utils/Eventbus.js';

/**
 * v-field
 * @author wangdasong
 * @date 2023.01.31
 */

export default {
    name: 'v-field',
    props: {
        idx: Number,
        value: [String, Number, Object, Boolean],
        type: {
            // special type: point、rgba
            type: String,
            default: 'text'
        },
        name: String,
        label: String,
        placeholder: String,
        options: {
            // when type is select, [{ lable, value }]
            type: Array,
            default: () => []
        },
        validator: Object, // for v-validator
        focus: Function,
        plain: Boolean
    },
    components: {},
    data() {
        return {
            currentValue: this.value,
            currentValueHex: '',
            boxStyle: {},
            hexBoxCols: [],
            dragging: false,
            dropdownBoxVisible: false,
            usedColors: []
        };
    },
    computed: {},
    watch: {
        value: {
            handler(val) {
                this.currentValue = val;
                // console.log(`v-field.${this._uid}.watch.value: `, val);
            },
            deep: true
        },
        currentValue(val) {
            // console.log(`v-field.${this._uid}.watch.currentValue: `, val);
            this.$emit('input', val);
            this.setColor(val);
        }
    },
    created() {
        if (this.type === 'switch' && this.name) bus.on(`${this.name}.clearSwitch`, this.clearSwitch);
    },
    mounted() {
        this.init();
    },
    beforeDestroy() {
        if (this.type === 'switch' && this.name) bus.off(`${this.name}.clearSwitch`, this.clearSwitch);
    },
    methods: {
        init() {
            if (this.type === 'point' && !this.currentValue) this.currentValue = { x: 0, y: 0 };
            else if (this.type === 'rgba' && !this.currentValue) this.currentValue = 'rgba(0,0,0,0)';
            // else if (this.type === 'rgba' && !this.currentValue) this.setColor('rgba(0,0,0,0)');
            // console.log(`v-field.${this._uid}.init: `, this.currentValue, this.type);
            if (this.type === 'rgba') this.setColor(this.currentValue);
            this.updateColors();
        },
        handleFocus() {
            // console.log('v-field.handleFocus: ', ...arguments);
            this.$emit('focus');
        },
        clearSwitch() {
            this.currentValue = false;
        },
        hanldeSwitch() {
            let c = this.currentValue;
            bus.emit(`${this.name}.clearSwitch`);
            this.currentValue = !c;
        },
        handleChange() {
            this.$emit('change', this.currentValue);
        },

        closeDropdownBoxListener(e) {
            if (e.target.parentNode === this.$refs.dropdownBox) return;

            e.stopPropagation();
            this.dropdownBoxVisible = false;
            window.document.removeEventListener('pointerdown', this.closeDropdownBoxListener, true);
        },
        openDropdownBoxListener(e) {
            if (this.dropdownBoxVisible) return;
            if (this.currentValue && !this.currentValueHex) this.setColor(this.currentValue);
            // console.log('v-field.handleDropdown: ', ...arguments);
            this.dropdownBoxVisible = true;
            e.stopPropagation();
            window.document.addEventListener('pointerdown', this.closeDropdownBoxListener, true);
        },
        getColor(index, value, hexString) {
            let hexValues = (hexString || this.currentValueHex).split(' ');
            if (typeof index !== 'undefined') {
                if (hexValues.length !== 4) hexValues = [0, 0, 0, 0];
                hexValues[index] = Expert.getHexString(value);
            } else if (hexValues.length !== 4) return '?';

            let color = 'rgba(';

            color += parseInt(hexValues[0], 16) + ',';
            color += parseInt(hexValues[1], 16) + ',';
            color += parseInt(hexValues[2], 16) + ',';
            color += Utils.round22(parseInt(hexValues[3], 16) / 255) + ')';

            return color;
        },
        setColor(col) {
            // when type equals 'rgba'
            // console.log(`v-field.${this._uid}.setColor: `, this.$refs.colorBox);
            if (!this.$refs.colorBox) return;
            let vs = Utils.colorToByteArray(col, this.$refs.colorBox);
            this.boxStyle = { background: 'rgba(' + vs[0] + ',' + vs[1] + ',' + vs[2] + ',' + vs[3] / 255 + ')' };
            this.currentValueHex = Utils.rgbaToHexString(vs);
            // console.warn('v-field.setColor: ', vs, this.currentValue);

            let cols = [];
            for (var i = 0; i < 4; i++) {
                var c1 = this.getColor(i, 255);
                var c2 = this.getColor(i, 0);

                cols.push({
                    style: { background: 'linear-gradient(0,' + c1 + ',' + c2 + ')' },
                    childStyle: { top: Math.round((vs[i] / 255) * 200) - 7 + 'px' }
                });
            }
            this.hexBoxCols = cols;

            if (!this.usedColors || !this.usedColors.length) this.updateColors();
        },
        getTrimmedPointerY(offsetY, target) {
            return Math.max(0, Math.min(255, Math.round((offsetY / target.clientHeight) * 255)));
        },
        colPointerDownListener(e, idx) {
            this.dragging = true;
            let target = e.target || e.srcElement,
                offsetY = DOM.getMouseOffset(e, target).y;
            // startY = offsetY - DOM.getPointerPagePos(e).y;
            this.startY = offsetY - DOM.getPointerPagePos(e).y;
            this.colIndex = idx;
            this.setColor(this.getColor(idx, this.getTrimmedPointerY(offsetY, target)));
            // console.warn('v-field.colPointerDownListener: ', ...arguments);

            window.document.addEventListener('mousemove', _.throttle(this.pointerMoveListener, 50));
            window.document.addEventListener('touchmove', _.throttle(this.pointerMoveListener, 50));
            window.document.addEventListener('mouseup', this.pointerUpListener);
            window.document.addEventListener('touchend', this.pointerUpListener);
        },
        pointerMoveListener(e) {
            e.preventDefault();
            if (!this.dragging) return;

            let target = e.target || e.srcElement,
                offsetY = this.startY + DOM.getPointerPagePos(e).y;
            this.setColor(this.getColor(this.colIndex, this.getTrimmedPointerY(offsetY, target)));
            // if (this.inputCallback) this.inputCallback.call(this);
        },
        pointerUpListener() {
            this.dragging = false;
            window.document.removeEventListener('mousemove', _.throttle(this.pointerMoveListener, 50));
            window.document.removeEventListener('touchmove', _.throttle(this.pointerMoveListener, 50));
            window.document.removeEventListener('mouseup', this.pointerUpListener);
            window.document.removeEventListener('touchend', this.pointerUpListener);
        },
        updateColors() {
            let colors = [],
                paths = this.$root.resources.paths,
                contours = this.$root.resources.contours,
                h1,
                h2;
            if (!paths || !contours) return;
            for (let i = 0, len = paths.length; i < len; i++) {
                h1 = Utils.rgbaToHexString(paths[i].color);
                h2 = Utils.rgbaToHexString(paths[i].labelColor);

                if (colors.indexOf(h1) < 0) colors.push(h1);
                if (colors.indexOf(h2) < 0) colors.push(h2);
            }
            for (let i = 0, len = contours.length; i < len; i++) {
                h1 = Utils.rgbaToHexString(contours[i].color);
                h2 = Utils.rgbaToHexString(contours[i].labelColor);

                if (colors.indexOf(h1) < 0) colors.push(h1);
                if (colors.indexOf(h2) < 0) colors.push(h2);
            }
            // // remove old preset boxes
            // var index = this.dropdownBox.children.length;
            // while (index-- > 4) this.dropdownBox.removeChild(this.dropdownBox.children[index]);

            // add new preset boxes
            let cols = [];
            for (let i = 0, len = colors.length; i < len; i++) {
                // var box = document.createElement('div');
                // box.className = 'rgbaInputPresetBox';
                // box.style.background = this.getColor(null, null, colors[i]);
                // box.onclick = function ()
                // {
                //     self.setColor(this.style.background);
                // };
                // this.dropdownBox.appendChild(box);
                cols.push({
                    class: 'rgbaInputPresetBox',
                    style: { background: this.getColor(null, null, colors[i]) }
                });
            }
            this.usedColors = cols;
        }
    }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<!-- <style scoped lang="scss"> -->
<style lang="scss">
.v-field {
    vertical-align: top;
    // padding: 3px;

    // display: flex;
    // align-items: center;
    // display: inline-block;

    .lab {
        min-width: 80px;
        text-align: left;
        line-height: 1;
        margin: 0 6px 0 0;
    }

    input,
    select {
        // width: 160px;
        width: 100%;
        border: none;
        background-color: transparent;
    }
    .placeholder {
        color: #dcdfe6;
    }

    &.switch {
        cursor: pointer;
    }

    &.point {
        input {
            width: 60px;
        }
    }

    &.plain {
        display: flex;
        align-items: center;
        justify-content: space-between;

        .lab {
            display: inline-block;
        }

        .con {
            width: 60%;
            height: 100%;
            text-align: left;
        }

        input,
        select {
            // width: 60px;
            height: 100%;
            // text-align: right;

            &:last-child {
                margin: 0 0 0 -1px;
            }
        }
    }

    &.error {
        background-color: #dcccd3;
    }

    .rgbaInputFrame {
        position: relative;
        height: 26px;
        background-color: white;
        background-image: linear-gradient(+45deg, silver 25%, transparent 25%),
            linear-gradient(-45deg, silver 25%, transparent 25%), linear-gradient(+45deg, transparent 75%, silver 75%),
            linear-gradient(-45deg, transparent 75%, silver 75%);
        background-size: 12px 12px;
        background-position: 1px 1px, 1px 7px, 7px -5px, -5px 1px;
    }

    .rgbaInputColorBox {
        float: left;
        width: 26px;
        height: 26px;
        border: 1px solid silver;
        box-sizing: border-box;
    }

    .rgbaInputHexBox {
        float: left;
        width: 90px;
        height: 26px;
        padding: 4px;
        margin-left: -1px;
        overflow: hidden;
        background-color: white;
        border: 1px solid silver;
        box-sizing: border-box;
        text-align: center;
    }

    .rgbaDropdownBox {
        width: 100%;
        position: absolute;
        display: flex;
        flex-wrap: wrap;
        top: 26px;
        left: 0;
        background-color: white;
        border: 1px solid #878787;
        border-left: none;
        box-sizing: border-box;
        z-index: 1;
    }

    .rgbaDropdownBoxColumn {
        flex-basis: 25%;
        height: 200px;
        position: relative;
        border-left: 1px solid #878787;
        box-shadow: 0 0 10px #aaa inset;
        overflow: hidden;
        box-sizing: border-box;
    }

    .rgbaDropdownBoxMarker {
        position: relative;
        top: -7px;
        left: 0;
        border-top: 7px solid transparent;
        border-bottom: 7px solid transparent;
        border-left: 7px solid black;
        pointer-events: none;
    }

    .rgbaInputPresetBox {
        flex-grow: 1;
        height: 11px;
        min-width: 11px;
        border-left: 1px solid black;
        border-top: 1px solid black;
        box-sizing: border-box;
    }
}
.v-field .p-path-picker {
    select {
        // width: 60px;
        height: 100%;
    }
}
</style>
